package com.wugh.fast.kernel.util;

import com.wugh.fast.kernel.core.exception.FastGlobalException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * 树编码工具
 *
 * @author 吴冠辉
 * @date 2018/6/26 15:13
 */
@Slf4j
public class TreeCodeUtils {
    private TreeCodeUtils() {
    }

    /**
     * 树编码填充字符串
     */
    public static final String TREE_CODE_PAD_CHAR = "0";

    /**
     * 根据父节点和兄弟节点,生成可用的节点
     *
     * @param parentCode   父节点
     * @param siblingCodes 兄弟节点的集合
     * @param codeLength   每层的长度
     * @return
     */
    public static String getChildrenCode(String parentCode, Collection<String> siblingCodes, Integer codeLength) {
        if (parentCode == null) {
            parentCode = "";
        }
        if (siblingCodes == null) {
            siblingCodes = new ArrayList<>(0);
        }
        Set<Integer> siblingNums = new HashSet<>(siblingCodes.size());
        //判断 兄弟和是否都属于父节点
        for (String siblingCode : siblingCodes) {
            String msg = String.format("异常的树编码数据:父节点[%s],兄弟节点[%s],长度[%s]", parentCode, siblingCode, codeLength);
            //父节点和兄弟节点的关系检测
            if (!siblingCode.startsWith(parentCode)) {
                log.error(msg);
                throw new FastGlobalException(msg);
            }
            //剩余的编码
            String remainderCode = StringUtils.removeStart(siblingCode, parentCode);
            // 剩余的长度检测
            if (remainderCode.length() != codeLength) {
                log.error(msg);
                throw new FastGlobalException(msg);
            }
            int siblingNum = Integer.parseInt(remainderCode);
            if (siblingNums.contains(siblingNum)) {
                String duplicateError = String.format("兄弟节点重复:%s", siblingCode);
                //兄弟的节点重复,有问题
                log.error(duplicateError);
                throw new FastGlobalException(duplicateError);
            }
            siblingNums.add(siblingNum);
        }
        Integer max = siblingNums.stream().max(Integer::compareTo).orElse(0);
        Integer currentNum = max + 1;
        for (int i = 1; i <= max + 1; i++) {
            if (!siblingNums.contains(i)) {
                currentNum = i;
                break;
            }
        }
        if (currentNum >= Math.pow(10, codeLength)) {
            String msg = String.format("节点范围溢出,当前序号:%s,每层大小:%s", currentNum, codeLength);
            log.error(msg);
            throw new FastGlobalException(msg);
        }
        return parentCode + StringUtils.leftPad("" + currentNum, codeLength, TREE_CODE_PAD_CHAR);
    }
}
